<template>
  <el-card class="content-card" shadow="hover">
    <template #header>
      <div class="card-header">
        <span>API文档 - 最佳实践</span>
      </div>
    </template>

    <div class="content-container">
      <div class="api-content">
        <div class="section" id="intro">
          <div class="section-header"><h2>最佳实践介绍</h2></div>
          <p class="intro-text">
            本页面提供了使用我们API的最佳实践和推荐方法，帮助您构建高效、可靠且易于维护的应用程序。
            遵循这些最佳实践可以提高应用性能、降低错误率，并确保良好的用户体验。
          </p>
        </div>

        <div class="section" id="architecture">
          <div class="section-header"><h2>架构设计</h2></div>
          <p>设计良好的架构是构建可靠API应用的基础：</p>
          <div class="best-practice-card">
            <h3>API客户端封装</h3>
            <p>创建一个专门的API客户端层，封装所有API调用逻辑：</p>
            <div class="code-block">
              <div class="code-header">
                <span>JavaScript</span>
                <el-button
                  type="primary"
                  size="small"
                  :icon="CopyDocument"
                  @click="copyCode(clientCode)"
                  class="copy-btn"
                >
                  复制代码
                </el-button>
              </div>
              <MonacoEditor
                style="height: 200px; border-radius: 6px; overflow: hidden"
                v-model="clientCode"
                language="javascript"
                :options="{
                  readOnly: true,
                  minimap: { enabled: false },
                  height: '200px',
                }"
              />
            </div>
          </div>
        </div>

        <div class="section" id="error-handling">
          <div class="section-header"><h2>错误处理</h2></div>
          <p>健壮的错误处理是可靠应用的关键：</p>
          <div class="best-practice-card">
            <h3>集中式错误处理</h3>
            <p>实现集中式错误处理机制，统一管理API错误：</p>
            <div class="code-block">
              <div class="code-header">
                <span>JavaScript</span>
                <el-button
                  type="primary"
                  size="small"
                  :icon="CopyDocument"
                  @click="copyCode(errorHandlingCode)"
                  class="copy-btn"
                >
                  复制代码
                </el-button>
              </div>
              <MonacoEditor
                style="height: 200px; border-radius: 6px; overflow: hidden"
                v-model="errorHandlingCode"
                language="javascript"
                :options="{
                  readOnly: true,
                  minimap: { enabled: false },
                  height: '200px',
                }"
              />
            </div>
          </div>
        </div>

        <div class="section" id="performance">
          <div class="section-header"><h2>性能优化</h2></div>
          <p>优化API调用性能，提高应用响应速度：</p>
          <div class="best-practice-card">
            <h3>请求优化</h3>
            <ul class="practice-list">
              <li>
                <strong>减少请求次数：</strong>
                合并多个请求，使用批量操作API，减少网络往返
              </li>
              <li>
                <strong>按需加载数据：</strong>
                使用分页、筛选和字段选择，只获取必要的数据
              </li>
              <li>
                <strong>并行请求：</strong>
                使用Promise.all并行处理独立的API请求
              </li>
              <li>
                <strong>缓存策略：</strong>
                缓存不经常变化的数据，减少重复请求
              </li>
            </ul>
            <div class="code-block">
              <div class="code-header">
                <span>JavaScript</span>
                <el-button
                  type="primary"
                  size="small"
                  :icon="CopyDocument"
                  @click="copyCode(performanceCode)"
                  class="copy-btn"
                >
                  复制代码
                </el-button>
              </div>
              <MonacoEditor
                style="height: 200px; border-radius: 6px; overflow: hidden"
                v-model="performanceCode"
                language="javascript"
                :options="{
                  readOnly: true,
                  minimap: { enabled: false },
                  height: '200px',
                }"
              />
            </div>
          </div>
        </div>

        <div class="section" id="security">
          <div class="section-header"><h2>安全最佳实践</h2></div>
          <p>保护您的应用和用户数据安全：</p>
          <div class="best-practice-card">
            <h3>API密钥管理</h3>
            <ul class="practice-list">
              <li>
                <strong>安全存储：</strong>
                永远不要在客户端代码中硬编码API密钥
              </li>
              <li>
                <strong>环境变量：</strong>
                使用环境变量或安全的配置管理系统存储密钥
              </li>
              <li>
                <strong>最小权限：</strong>
                为不同环境使用不同的API密钥，并限制其权限
              </li>
              <li>
                <strong>密钥轮换：</strong>
                定期更换API密钥，特别是在人员变动或可能泄露时
              </li>
            </ul>
            <div class="code-block">
              <div class="code-header">
                <span>JavaScript</span>
                <el-button
                  type="primary"
                  size="small"
                  :icon="CopyDocument"
                  @click="copyCode(securityCode)"
                  class="copy-btn"
                >
                  复制代码
                </el-button>
              </div>
              <MonacoEditor
                style="height: 200px; border-radius: 6px; overflow: hidden"
                v-model="securityCode"
                language="javascript"
                :options="{
                  readOnly: true,
                  minimap: { enabled: false },
                  height: '200px',
                }"
              />
            </div>
          </div>
        </div>

        <div class="section" id="testing">
          <div class="section-header"><h2>测试策略</h2></div>
          <p>全面的测试确保API集成的可靠性：</p>
          <div class="best-practice-card">
            <h3>API集成测试</h3>
            <p>实现全面的API测试策略：</p>
            <div class="code-block">
              <div class="code-header">
                <span>JavaScript</span>
                <el-button
                  type="primary"
                  size="small"
                  :icon="CopyDocument"
                  @click="copyCode(testingCode)"
                  class="copy-btn"
                >
                  复制代码
                </el-button>
              </div>
              <MonacoEditor
                style="height: 200px; border-radius: 6px; overflow: hidden"
                v-model="testingCode"
                language="javascript"
                :options="{
                  readOnly: true,
                  minimap: { enabled: false },
                  height: '200px',
                }"
              />
            </div>
          </div>
        </div>
      </div>

      <!-- 右侧悬浮目录 -->
      <div class="toc">
        <div class="toc-title">目录</div>
        <div class="toc-item" @click="scrollToSection('intro')">
          最佳实践介绍
        </div>
        <div class="toc-item" @click="scrollToSection('architecture')">
          架构设计
        </div>
        <div class="toc-item" @click="scrollToSection('error-handling')">
          错误处理
        </div>
        <div class="toc-item" @click="scrollToSection('performance')">
          性能优化
        </div>
        <div class="toc-item" @click="scrollToSection('security')">
          安全最佳实践
        </div>
        <div class="toc-item" @click="scrollToSection('testing')">
          测试策略
        </div>
      </div>
    </div>
  </el-card>
</template>

<script setup>
import { ref } from 'vue';
import { CopyDocument } from '@element-plus/icons-vue';
import MonacoEditor from '@/components/MonacoEditor.vue';

// 示例代码
const clientCode = ref(`// api/client.js - API客户端封装
import axios from 'axios';
import { handleApiError } from './errorHandler';
import { getCachedData, setCachedData } from './cacheManager';

// 创建API客户端类
class ApiClient {
  constructor(config) {
    this.apiKey = config.apiKey;
    this.baseURL = config.baseURL || 'https://api.example.com/v1';
    this.timeout = config.timeout || 30000;
    
    // 创建axios实例
    this.client = axios.create({
      baseURL: this.baseURL,
      timeout: this.timeout,
      headers: {
        'Content-Type': 'application/json',
        'Authorization': \`Bearer \${this.apiKey}\`,
        'X-Client-Version': '1.0.0'
      }
    });
    
    // 添加请求拦截器
    this.client.interceptors.request.use(
      config => {
        // 在发送请求前做些什么
        console.log(\`发送请求: \${config.method.toUpperCase()} \${config.url}\`);
        return config;
      },
      error => {
        // 处理请求错误
        return Promise.reject(error);
      }
    );
    
    // 添加响应拦截器
    this.client.interceptors.response.use(
      response => {
        // 处理响应数据
        return response;
      },
      error => {
        // 处理响应错误
        return handleApiError(error);
      }
    );
    
    // 初始化API模块
    this.data = {
      getList: this.createApiMethod('GET', '/data'),
      getDetail: this.createApiMethod('GET', '/data/{id}'),
      create: this.createApiMethod('POST', '/data'),
      update: this.createApiMethod('PUT', '/data/{id}'),
      delete: this.createApiMethod('DELETE', '/data/{id}'),
      batchCreate: this.createApiMethod('POST', '/data/batch'),
      advancedSearch: this.createApiMethod('POST', '/data/search')
    };
  }
  
  // 创建API方法
  createApiMethod(method, endpoint) {
    return async (params = {}, options = {}) => {
      // 检查缓存
      if (method === 'GET' && options.useCache !== false) {
        const cachedData = getCachedData(endpoint, params);
        if (cachedData) return cachedData;
      }
      
      // 处理URL参数
      let url = endpoint;
      if (params.id && url.includes('{id}')) {
        url = url.replace('{id}', params.id);
        delete params.id;
      }
      
      // 发送请求
      try {
        let response;
        if (method === 'GET') {
          response = await this.client.get(url, { params });
        } else {
          response = await this.client[method.toLowerCase()](url, params);
        }
        
        // 缓存GET请求结果
        if (method === 'GET' && options.useCache !== false) {
          setCachedData(endpoint, params, response, options.cacheTTL);
        }
        
        return response;
      } catch (error) {
        console.error(\`API请求失败: \${method} \${url}\`, error);
        throw error;
      }
    };
  }
  
  // 获取API密钥
  getApiKey() {
    return this.apiKey;
  }
}

// 导出API客户端实例创建函数
export function createApiClient(config) {
  return new ApiClient(config);
}`);

const errorHandlingCode = ref(`// api/errorHandler.js - 集中式错误处理
import { ElMessage } from 'element-plus';

// 错误类型映射
const ERROR_TYPES = {
  NETWORK_ERROR: 'network_error',
  TIMEOUT_ERROR: 'timeout_error',
  AUTH_ERROR: 'auth_error',
  PERMISSION_ERROR: 'permission_error',
  RESOURCE_ERROR: 'resource_error',
  VALIDATION_ERROR: 'validation_error',
  SERVER_ERROR: 'server_error',
  UNKNOWN_ERROR: 'unknown_error'
};

// 用户友好的错误消息
const ERROR_MESSAGES = {
  [ERROR_TYPES.NETWORK_ERROR]: '网络连接错误，请检查您的网络连接',
  [ERROR_TYPES.TIMEOUT_ERROR]: '请求超时，请稍后重试',
  [ERROR_TYPES.AUTH_ERROR]: '认证失败，请重新登录',
  [ERROR_TYPES.PERMISSION_ERROR]: '您没有权限执行此操作',
  [ERROR_TYPES.RESOURCE_ERROR]: '请求的资源不存在',
  [ERROR_TYPES.VALIDATION_ERROR]: '请求数据验证失败',
  [ERROR_TYPES.SERVER_ERROR]: '服务器内部错误，请稍后重试',
  [ERROR_TYPES.UNKNOWN_ERROR]: '发生未知错误，请稍后重试'
};

// 确定错误类型
function determineErrorType(error) {
  if (!error.response) {
    // 网络错误或请求被取消
    if (error.code === 'ECONNABORTED') {
      return ERROR_TYPES.TIMEOUT_ERROR;
    }
    return ERROR_TYPES.NETWORK_ERROR;
  }
  
  // 根据HTTP状态码确定错误类型
  const status = error.response.status;
  
  switch (status) {
    case 400:
      return ERROR_TYPES.VALIDATION_ERROR;
    case 401:
      return ERROR_TYPES.AUTH_ERROR;
    case 403:
      return ERROR_TYPES.PERMISSION_ERROR;
    case 404:
      return ERROR_TYPES.RESOURCE_ERROR;
    case 500:
    case 502:
    case 503:
    case 504:
      return ERROR_TYPES.SERVER_ERROR;
    default:
      return ERROR_TYPES.UNKNOWN_ERROR;
  }
}

// 处理API错误
export function handleApiError(error) {
  // 确定错误类型
  const errorType = determineErrorType(error);
  
  // 获取错误详情
  const errorDetails = {
    type: errorType,
    message: ERROR_MESSAGES[errorType],
    originalError: error,
    timestamp: new Date().toISOString()
  };
  
  // 添加响应数据（如果有）
  if (error.response && error.response.data) {
    errorDetails.responseData = error.response.data;
    
    // 使用服务器返回的错误消息（如果有）
    if (error.response.data.message) {
      errorDetails.message = error.response.data.message;
    }
  }
  
  // 记录错误
  console.error('API错误:', errorDetails);
  
  // 显示用户友好的错误消息
  ElMessage.error(errorDetails.message);
  
  // 特殊错误处理
  if (errorType === ERROR_TYPES.AUTH_ERROR) {
    // 重定向到登录页或刷新token
    console.log('重定向到登录页...');
    // router.push('/login');
  }
  
  // 返回被拒绝的Promise，保持错误传播
  return Promise.reject(errorDetails);
}`);

const performanceCode = ref(`// 性能优化示例

// 1. 并行请求
async function loadDashboardData(userId) {
  try {
    // 并行发起多个独立的API请求
    const [userProfile, userStats, recentActivities] = await Promise.all([
      apiClient.users.getProfile({ id: userId }),
      apiClient.users.getStats({ id: userId }),
      apiClient.activities.getRecent({ userId, limit: 5 })
    ]);
    
    return {
      profile: userProfile.data,
      stats: userStats.data,
      activities: recentActivities.data
    };
  } catch (error) {
    console.error('加载仪表板数据失败:', error);
    throw error;
  }
}

// 2. 按需加载数据
async function loadTableData(filters, pagination) {
  try {
    // 只请求当前页面需要的数据
    const response = await apiClient.data.getList({
      // 分页参数
      page: pagination.currentPage,
      pageSize: pagination.pageSize,
      
      // 排序参数
      sortBy: pagination.sortBy,
      sortOrder: pagination.sortOrder,
      
      // 筛选参数
      ...filters,
      
      // 只选择需要的字段
      fields: ['id', 'title', 'status', 'createdAt', 'updatedAt']
    });
    
    return response.data;
  } catch (error) {
    console.error('加载表格数据失败:', error);
    throw error;
  }
}

// 3. 防抖搜索
import { debounce } from 'lodash';

// 创建防抖搜索函数
const debouncedSearch = debounce(async (searchTerm, callback) => {
  try {
    const response = await apiClient.data.search({ query: searchTerm });
    callback(response.data);
  } catch (error) {
    console.error('搜索失败:', error);
    callback([], error);
  }
}, 300); // 300ms延迟`);

const securityCode = ref(`// 安全最佳实践示例

// 1. 安全的API密钥管理
// config.js - 使用环境变量
export const apiConfig = {
  apiKey: process.env.VUE_APP_API_KEY, // 从环境变量获取API密钥
  baseURL: process.env.VUE_APP_API_BASE_URL,
  environment: process.env.NODE_ENV
};

// 2. 敏感数据处理
function sanitizeUserData(userData) {
  // 创建一个新对象，只包含需要的非敏感字段
  const sanitized = {
    id: userData.id,
    username: userData.username,
    email: userData.email,
    displayName: userData.displayName,
    avatar: userData.avatar,
    createdAt: userData.createdAt,
    lastLogin: userData.lastLogin
  };
  
  // 确保不包含敏感信息
  delete sanitized.password;
  delete sanitized.passwordHash;
  delete sanitized.securityQuestions;
  delete sanitized.apiKeys;
  
  return sanitized;
}

// 3. 输入验证
import { z } from 'zod';

// 定义验证模式
const userInputSchema = z.object({
  username: z.string().min(3).max(50),
  email: z.string().email(),
  password: z.string().min(8).regex(/[A-Z]/).regex(/[0-9]/).regex(/[^A-Za-z0-9]/),
  age: z.number().int().min(18).optional()
});

// 验证用户输入
function validateUserInput(input) {
  try {
    // 验证并返回解析后的数据
    const validData = userInputSchema.parse(input);
    return { isValid: true, data: validData };
  } catch (error) {
    // 返回验证错误
    return { 
      isValid: false, 
      errors: error.errors.map(e => ({
        path: e.path.join('.'),
        message: e.message
      }))
    };
  }
}`);

const testingCode = ref(`// API测试策略示例
import { expect } from 'chai';
import sinon from 'sinon';
import { createApiClient } from '../api/client';

// 模拟axios
const mockAxios = {
  create: sinon.stub().returns({
    get: sinon.stub(),
    post: sinon.stub(),
    put: sinon.stub(),
    delete: sinon.stub(),
    interceptors: {
      request: { use: sinon.stub() },
      response: { use: sinon.stub() }
    }
  })
};

// 单元测试API客户端
describe('API Client', () => {
  let apiClient;
  let axiosInstance;
  
  beforeEach(() => {
    // 重置模拟
    sinon.reset();
    
    // 创建API客户端实例
    apiClient = createApiClient({
      apiKey: 'test-api-key',
      baseURL: 'https://api.example.com/v1',
      axios: mockAxios // 注入模拟axios
    });
    
    axiosInstance = mockAxios.create.firstCall.returnValue;
  });
  
  describe('data.getList', () => {
    it('应该发送正确的GET请求', async () => {
      // 设置模拟响应
      const mockResponse = {
        data: [{ id: 1, name: 'Test' }],
        status: 200
      };
      axiosInstance.get.resolves(mockResponse);
      
      // 调用API方法
      const params = { page: 1, pageSize: 10 };
      const response = await apiClient.data.getList(params);
      
      // 验证请求
      expect(axiosInstance.get.calledOnce).to.be.true;
      expect(axiosInstance.get.firstCall.args[0]).to.equal('/data');
      expect(axiosInstance.get.firstCall.args[1]).to.deep.equal({ params });
      
      // 验证响应
      expect(response).to.equal(mockResponse);
    });
    
    it('应该处理错误', async () => {
      // 设置模拟错误
      const mockError = new Error('Network Error');
      axiosInstance.get.rejects(mockError);
      
      // 调用API方法并捕获错误
      try {
        await apiClient.data.getList();
        // 如果没有抛出错误，测试应该失败
        expect.fail('应该抛出错误');
      } catch (error) {
        // 验证错误处理
        expect(error.type).to.equal('network_error');
        expect(error.originalError).to.equal(mockError);
      }
    });
  });
  
  // 更多测试...
});

// 集成测试
describe('API Integration', () => {
  // 使用真实API进行测试
  const apiClient = createApiClient({
    apiKey: process.env.TEST_API_KEY,
    baseURL: process.env.TEST_API_URL
  });
  
  it('应该能够完成完整的CRUD流程', async () => {
    // 创建测试数据
    const testData = {
      title: \`Test Item \${Date.now()}\`,
      content: 'This is a test item for integration testing'
    };
    
    // 1. 创建
    const createResponse = await apiClient.data.create(testData);
    expect(createResponse.status).to.equal(201);
    expect(createResponse.data).to.have.property('id');
    
    const itemId = createResponse.data.id;
    
    // 2. 读取
    const getResponse = await apiClient.data.getDetail({ id: itemId });
    expect(getResponse.status).to.equal(200);
    expect(getResponse.data.title).to.equal(testData.title);
    
    // 3. 更新
    const updateData = {
      title: \`Updated Test Item \${Date.now()}\`
    };
    const updateResponse = await apiClient.data.update({ id: itemId, ...updateData });
    expect(updateResponse.status).to.equal(200);
    
    // 验证更新
    const getUpdatedResponse = await apiClient.data.getDetail({ id: itemId });
    expect(getUpdatedResponse.data.title).to.equal(updateData.title);
    
    // 4. 删除
    const deleteResponse = await apiClient.data.delete({ id: itemId });
    expect(deleteResponse.status).to.equal(204);
    
    // 验证删除
    try {
      await apiClient.data.getDetail({ id: itemId });
      expect.fail('应该抛出404错误');
    } catch (error) {
      expect(error.type).to.equal('resource_error');
    }
  });
});
`);

// 复制代码功能
const copyCode = (code) => {
  navigator.clipboard.writeText(code.value)
    .then(() => {
      ElMessage.success('代码已复制到剪贴板');
    })
    .catch(() => {
      ElMessage.error('复制失败');
    });
};

// 滚动到指定区域
const scrollToSection = (sectionId) => {
  const element = document.getElementById(sectionId);
  if (element) {
    element.scrollIntoView({ behavior: "smooth" });
  }
};
</script>

<style scoped>
.content-card {
  height: 100%;
  display: flex;
  flex-direction: column;
  position: relative;
  border-radius: 12px;
  overflow: hidden;
  background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
}

.card-header {
  box-sizing: border-box;
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 18px;
  font-weight: 500;
  color: #303133;
}

:deep(.el-card__body) {
  padding: 0;
  height: calc(100% - 60px);
  overflow-y: auto;
  background: #ffffff;
}

.content-container {
  min-height: 100%;
  padding: 30px;
  padding-right: 280px;
  background: linear-gradient(to bottom, #ffffff 0%, #f8f9fa 100%);
}

.api-content {
  max-width: 1000px;
  margin: 0 auto;
  line-height: 1.8;
  color: #4a5568;
}

.section {
  margin-bottom: 40px;
  padding: 0;
}

.section-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 20px;
}

.section h2 {
  margin: 0;
  padding-bottom: 10px;
  border-bottom: 2px solid #409eff;
  color: #303133;
  font-size: 20px;
  font-weight: 600;
  position: relative;
  flex: 1;
}

.section h2::before {
  content: "";
  position: absolute;
  left: 0;
  bottom: -2px;
  width: 50px;
  height: 2px;
  background: #409eff;
  border-radius: 1px;
}

.intro-text {
  font-size: 16px;
  line-height: 1.8;
  color: #4a5568;
  margin-bottom: 20px;
}

.best-practice-card {
  background-color: #f8f9fa;
  border-radius: 8px;
  padding: 20px;
  margin-bottom: 20px;
  border-left: 4px solid #409eff;
}

.best-practice-card h3 {
  margin-top: 0;
  margin-bottom: 15px;
  color: #303133;
}

.practice-list {
  padding-left: 20px;
  margin-bottom: 20px;
}

.practice-list li {
  margin-bottom: 10px;
  line-height: 1.5;
}

.code-block {
  margin: 15px 0;
  border: 1px solid #dcdfe6;
  border-radius: 6px;
  overflow: hidden;
}

.code-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 8px 15px;
  background-color: #f5f7fa;
  border-bottom: 1px solid #dcdfe6;
}

.copy-btn {
  margin-left: 10px;
}

/* 右侧悬浮目录样式 */
.toc {
  position: fixed;
  right: 50px;
  top: 50%;
  transform: translateY(-50%);
  background: #ffffff;
  padding: 20px;
  border-radius: 8px;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
  z-index: 1000;
  border: 1px solid #e4e7ed;
  min-width: 200px;
}

.toc-title {
  font-weight: 700;
  margin-bottom: 15px;
  color: #2d3748;
  font-size: 18px;
  text-align: center;
  padding-bottom: 10px;
  border-bottom: 2px solid #e2e8f0;
}

.toc-item {
  padding: 12px 16px;
  cursor: pointer;
  color: #4a5568;
  transition: all 0.3s ease;
  border-radius: 8px;
  font-size: 14px;
  margin-bottom: 4px;
  border-left: 3px solid transparent;
  position: relative;
}

.toc-item:hover {
  color: #409eff;
  background: #ecf5ff;
  border-left-color: #409eff;
  transform: translateX(4px);
}

.toc-item:active {
  transform: translateX(2px);
}

/* 响应式设计 */
@media (max-width: 1400px) {
  .content-container {
    padding-right: 30px;
  }

  .toc {
    display: none;
  }
}

@media (max-width: 768px) {
  .content-container {
    padding: 20px 15px;
  }

  .section {
    padding: 20px 15px;
    margin-bottom: 25px;
  }

  .section h2 {
    font-size: 18px;
  }

  .card-header {
    font-size: 16px;
    padding: 15px;
  }
}

/* 滚动条样式 */
:deep(.el-card__body)::-webkit-scrollbar {
  width: 6px;
}

:deep(.el-card__body)::-webkit-scrollbar-track {
  background: #f1f1f1;
  border-radius: 3px;
}

:deep(.el-card__body)::-webkit-scrollbar-thumb {
  background: #409eff;
  border-radius: 3px;
}

:deep(.el-card__body)::-webkit-scrollbar-thumb:hover {
  background: #337ecc;
}
</style>